package com.agileai.hotweb.common;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;

import com.agileai.hotweb.controller.core.BaseHandler;
import com.agileai.util.StringUtil;
import com.agileai.util.XmlUtil;

public class HandlerParser {
	private static HashMap<ClassLoader,HandlerParser> handlerParserCache = new HashMap<ClassLoader,HandlerParser>();

	private Map<String,String> classNameCache = new HashMap<String,String>();
	private Map<String,String> pageURLCache = new HashMap<String,String>();
	private Map<String,String> idReverseCache = new HashMap<String,String>();
	private ClassLoader handlerClassLoader = null;
	private ClassLoader handlerContextClassLoader = null;
	private Document document = null;
	
	private HandlerParser (){
	}
	public static HandlerParser getOnly(){
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		HandlerParser instance = handlerParserCache.get(classLoader);
		if (instance == null){
			try {
				instance = (HandlerParser)classLoader.loadClass("com.agileai.hotweb.common.HandlerParser").newInstance();			
				handlerParserCache.put(classLoader, instance);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return instance;
	}
	public static void init(String handlerConfigLocation){
		HandlerParser instance = getOnly();
		if (instance.document == null){
			InputStream configStream = null;
			if (instance.handlerContextClassLoader != null){
				configStream = instance.handlerContextClassLoader.getResourceAsStream(handlerConfigLocation);
			}else{
				configStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(handlerConfigLocation);				
			}
			instance.document = XmlUtil.readDocument(configStream);
		}
	}
	@SuppressWarnings("rawtypes")
	public BaseHandler instantiateHandler(String handlerId) throws InstantiationException, IllegalAccessException, ClassNotFoundException{
		String className = parseClassName(handlerId);
		ClassLoader classLoader = null;
		if (this.handlerClassLoader != null){
			classLoader = this.handlerClassLoader;
		}else{
			if (this.handlerContextClassLoader != null){
				classLoader = this.handlerContextClassLoader;
			}else{
				classLoader = Thread.currentThread().getContextClassLoader();				
			}
		}
		Class handlerClass = classLoader.loadClass(className);
		BaseHandler handler =  (BaseHandler)handlerClass.newInstance();
		if (handler != null){
			handler.setHandlerId(handlerId);
			String displayPage = paresePageURL(handlerId);
			if (!StringUtil.isNullOrEmpty(displayPage)){
				handler.setPage(displayPage);				
			}
		}
		return handler;
	}
	public String parseClassName(String handlerId){
		String result = null;
		if (!classNameCache.containsKey(handlerId)){
			String handlerPath = "//beans/bean[@id='"+handlerId+"']";
			Element handlerElement = (Element)document.selectSingleNode(handlerPath);
			String className = handlerElement.attribute("class").getText();
			classNameCache.put(handlerId, className);
		}
		result = classNameCache.get(handlerId);
		return result;
	}
	public String parseHandlerId(String handlerClazzName){
		String result = null;
		if (!idReverseCache.containsKey(handlerClazzName)){
			String handlerPath = "//beans/bean[@class='"+handlerClazzName+"']";
			Element handlerElement = (Element)document.selectSingleNode(handlerPath);
			String handlerId = handlerElement.attribute("id").getText();
			idReverseCache.put(handlerClazzName, handlerId);
		}
		result = idReverseCache.get(handlerClazzName);
		return result;
	}
	
	public String paresePageURL(String handlerId){
		String result = null;
		if (!pageURLCache.containsKey(handlerId)){
			String handlerPath = "//beans/bean[@id='"+handlerId+"']";
			Element handlerElement = (Element)document.selectSingleNode(handlerPath);
			Attribute attribute = handlerElement.attribute("page");
			String pageURL = "";
			if (attribute != null){
				pageURL = attribute.getText();			
			}
			pageURLCache.put(handlerId, pageURL);
		}
		result = pageURLCache.get(handlerId);
		return result;
	}
	
	public void setHandlerClassLoader(ClassLoader handlerClassLoader) {
		this.handlerClassLoader = handlerClassLoader;
	}
	
	public ClassLoader getHandlerContextClassLoader() {
		return handlerContextClassLoader;
	}
	
	public void setHandlerContextClassLoader(ClassLoader handlerContextClassLoader) {
		this.handlerContextClassLoader = handlerContextClassLoader;
	}	
}
